package control;
/* 
 * Diese Klasse ist für die Erstellung eines zufallsgenerierten Sudokus gedacht.
 */

import java.util.ArrayList;
import java.util.List;

import model.Sudoku;


public class SudokuGenerator {

	private Sudoku sudoku;
	
	public SudokuGenerator(Sudoku sudoku) {
		this.sudoku = sudoku;
	}
	
	//Erstelle die Zufallszahlen von 1-9
	public static byte generiereZufallsZahlen(byte byteHigh, byte byteLow){
		//byteHigh inkrementieren damit die obere Grenze stimmt
		byteHigh++;
		byte byteZufallsZahl;
		byteZufallsZahl = (byte) (Math.random() *(byteHigh - byteLow) + byteLow);
		return byteZufallsZahl;
	}
	
	public void erstelleLeichtesSpiel() {
		/*
		 * In dieser Methode werden 4 Zellen aus dem Sudoku gelöscht.
		 * Dadurch entsteht ein Sudoku mit einem leichten Schwierigkeitsgrad.
		 */
		
		// Als erstes wird eine Zelle aus den ersten 3 Zeilen gelöscht.
		// Zwischenspeichern der Zufallswerte
		byte byteZeile = generiereZufallsZahlen((byte)(2),(byte)(0));
		byte byteErsteSpalte = generiereZufallsZahlen((byte)(8),(byte)(0));
		sudoku.byteSudokuFeld[byteZeile][byteErsteSpalte] = 0;
		// Als nächstes wird eine Zelle aus den zweiten 3 Zeilen gelöscht.
		// Dabei wird keines aus der erst genutzten Spalte gelöscht.
		byte byteZweiteSpalte;
		do {
			byteZweiteSpalte = generiereZufallsZahlen((byte)(8),(byte)(0));
		} while (byteZweiteSpalte == byteErsteSpalte);
		byteZeile = generiereZufallsZahlen((byte)(5),(byte)(3));
		sudoku.byteSudokuFeld[byteZeile][byteZweiteSpalte] = 0;
		// Als nächstes wird eine Zelle aus den dritten 3 Zeilen gelöscht.
		// Dabe wird keines aus den erst genutzten Spalten gelöscht.
		byte byteDritteSpalte;
		do {
			byteDritteSpalte = generiereZufallsZahlen((byte)(8),(byte)(0));
		} while (byteZweiteSpalte == byteDritteSpalte || byteErsteSpalte == byteDritteSpalte);
		byteZeile = generiereZufallsZahlen((byte)(8),(byte)(6));
		sudoku.byteSudokuFeld[byteZeile][byteDritteSpalte] = 0;
		// Zuletzt wird eine zufällige Zahl aus dem ganzen Sudokufeld gelöscht.
		// Dabei darf dieses Feld natürlich noch nicht gelöscht sein.
		byte byteVierteSpalte=0;
		do {
			byteVierteSpalte = generiereZufallsZahlen((byte)(8),(byte)(0));
			byteZeile = generiereZufallsZahlen((byte)(8),(byte)(0));
		} while (sudoku.byteSudokuFeld[byteZeile][byteVierteSpalte] == 0);
		sudoku.byteSudokuFeld[byteZeile][byteVierteSpalte] = 0;
		
	}
	
	// Methode zum Eintragen in ein 3x3 Feld
	private void eintragenInDreierFeld(byte byteMinimaleZeile, byte byteMinimaleSpalte, byte byteAnzahlZufallsZahlen, byte byteMaximaleGleicheSpalteZeilen) {
		byte byteAktuelleLeereZellen = 0;
		sprungmarke:
		while (byteAktuelleLeereZellen < byteAnzahlZufallsZahlen) {
			// Ermitteln der Zufallszeile innerhalb des 3x3 Feldes
			byte byteZufallsZeile = generiereZufallsZahlen((byte)(byteMinimaleZeile+2), byteMinimaleZeile);
			// Ermitteln der Zufallsspalte innerhalb des 3x3 Feldes
			byte byteZufallsSpalte = generiereZufallsZahlen((byte)(byteMinimaleSpalte+2), byteMinimaleSpalte);
			// Überprüfen ob in der Zeile und der Spalte schon 2 Leere Felder vorhanden sind
			byte byteGleicheZeilen = 0;
			for (byte byteSpalte = 0; byteSpalte < 9; byteSpalte++) {
				if (sudoku.byteSudokuFeld[byteZufallsZeile][byteSpalte] == 0) {
					byteGleicheZeilen++;
					if (byteGleicheZeilen == byteMaximaleGleicheSpalteZeilen) {
						continue sprungmarke;
					}
				}
			}
			byte byteGleicheSpalten = 0;
			for (byte byteZeile = 0; byteZeile < 9; byteZeile++) {
				if (sudoku.byteSudokuFeld[byteZeile][byteZufallsSpalte] == 0) {
					byteGleicheSpalten++;
					if (byteGleicheSpalten == byteMaximaleGleicheSpalteZeilen) {
						continue sprungmarke;
					}
				}
			}
			// Löschen des Zufallsfeldes
			sudoku.byteSudokuFeld[byteZufallsZeile][byteZufallsSpalte] = 0;
			byteAktuelleLeereZellen++;
		}
	}
	
	public void erstelleMittleresSpiel() {
		/*
		 * In dieser Methode werden 1-3 Zellen pro 3x3 Feld und max. 3 pro Zeile 
		 * und Spalte gelöscht.
		 */
		
		// Hier werden die Zufallszahlen in die 3x3 Feld eingetragen.
		for (byte byteZeile=0; byteZeile < 3; byteZeile++) {
			for (byte byteSpalte=0; byteSpalte < 3; byteSpalte++) {
				// Als erstes wird die Anzahl der Zellen pro 3x3 Feld 
				// durch einen Zufallsgenerator ermittelt.
				byte byteUntergrenze = 1;
				byte byteObergrenze = 3;
				byte byteAnzahlZufallsZahlen = generiereZufallsZahlen(byteObergrenze, byteUntergrenze);
				// Anzahl der max leeren Zellen pro Zeile & Spalte
				byte byteMaximaleGleicheSpaltenZeilen = 3;
				// Im Anschluss werden sie in das Feld eingetragen
				eintragenInDreierFeld((byte)(byteZeile*3), (byte)(byteSpalte*3), byteAnzahlZufallsZahlen, byteMaximaleGleicheSpaltenZeilen);
			}
		}
		
	}
	
	public void erstelleSchweresSpiel() {
		/*
		 * In dieser Methode werden 3-5 Zellen pro 3x3 Feld und max 4 
		 * pro Zeile und Spalte gelöscht.
		 */
		
		// Hier werden die Zufallszahlen in die 3x3 Feld eingetragen.
				for (byte byteZeile=0; byteZeile < 3; byteZeile++) {
					for (byte byteSpalte=0; byteSpalte < 3; byteSpalte++) {
						// Als erstes wird die Anzahl der Zellen pro 3x3 Feld 
						// durch einen Zufallsgenerator ermittelt.
						byte byteUntergrenze = 3;
						byte byteObergrenze = 5;
						byte byteAnzahlZufallsZahlen = generiereZufallsZahlen(byteObergrenze, byteUntergrenze);
						// Anzahl der max leeren Zellen pro Zeile & Spalte
						byte byteMaximaleGleicheSpaltenZeilen = 5;
						// Im Anschluss werden sie in das Feld eingetragen
						eintragenInDreierFeld((byte)(byteZeile*3), (byte)(byteSpalte*3), byteAnzahlZufallsZahlen, byteMaximaleGleicheSpaltenZeilen);
					}
				}
	}
	
	public void initialisiereZufallsSudoku() {
		// Initialisiere das Sudoku mit Nullen
		sudoku.erstelleLeeresFeld();
		/* Da schon verwendete Zahlen nicht noch einmal eingef�gt werden sollen, 
		 * werden diese in eine Liste eingef�gt. 
		 * Dies vermindert die Wahrscheinlichkeit von �berlappungen.
		 */
		List<Byte> listSchonVerwendeteZahlen = new ArrayList<Byte>(9);
		//SudokuFeld durchlaufen und pro Feld eine zuf�llige Zahl eingeben
		for (byte byteZeile = 0; byteZeile < 3; byteZeile++) {
			for (byte byteSpalte = 0; byteSpalte < 3; byteSpalte++) {
				// Erstellen der Zufallszahl f�r die Zeile
				byte byteZufallsZeile = generiereZufallsZahlen((byte) (byteZeile * 3 + 2),(byte) (byteZeile * 3));
				// Erstellen der Zufallszahl f�r die Spalte
				byte byteZufallsSpalte = generiereZufallsZahlen((byte) (byteSpalte * 3 + 2),(byte)  (byteSpalte * 3));
				// Erstellen der zu schreibenden Zufallszahl
				byte byteZufallszahl;
				do {
					byteZufallszahl = generiereZufallsZahlen((byte) (9),(byte) (1));
				} while (listSchonVerwendeteZahlen.contains((Byte)(byteZufallszahl)));
				listSchonVerwendeteZahlen.add((Byte)(byteZufallszahl));
				sudoku.byteSudokuFeld[byteZufallsZeile][byteZufallsSpalte] = byteZufallszahl;
			}
		}
	}
	
	//Gebe das generierte Sudoku zur�ck
	public Sudoku getSudoku() {
		return sudoku;
	}
	
	//Gebe neues Sudoku ein
	public void setSudoku(Sudoku sudoku) {
		this.sudoku = sudoku;
	}
}
